import 'package:dio/dio.dart';
import 'package:flutter_enjoy_plus/constants/index.dart';
import 'package:flutter_enjoy_plus/utils/Emitter.dart';
import 'package:flutter_enjoy_plus/utils/toast.dart';
import 'package:flutter_enjoy_plus/utils/tokenManager.dart';
class Requestdio{
  // 1、创建dio实例
  final Dio _dio = Dio();
  Requestdio(){
    // 配置基地址和响应、请求时间
    _dio.options.baseUrl = GlobalVariable.baseUrl;
    _dio.options.connectTimeout =  const Duration(seconds:GlobalVariable.timeout);
    _dio.options.receiveTimeout =  const Duration(seconds:GlobalVariable.timeout);
    //针对一个对象连续的进行赋值可以用..的方式 
    // dio
    //   ..options.baseUrl = GlobalVariable.baseUrl
    //   ..options.connectTimeout =  const Duration(seconds:GlobalVariable.timeout)
    //   ..options.receiveTimeout =  const Duration(seconds:GlobalVariable.timeout);

    // 设置拦截器
    _registerInterceptors();
  }
  // get请求
  Future get(String url, {Map<String, dynamic>? params}) async {
    final res = await _dio.get(url, queryParameters: params);
    return _handleResult(res);
  }
  // post请求
  Future post(String url, {Map<String, dynamic>? data}) async {
    final res = await _dio.post(url, data: data);
    return _handleResult(res);
  }
  // 上传图片
  Future upload(String url, {FormData? data}) async {
    final res = await _dio.post(url, data: data);
    return _handleResult(res);
  }
  // put请求
  Future put(String url, {Map<String, dynamic>? data}) async {
    final res = await _dio.put(url, data: data);
    return _handleResult(res);
  }
  // delete请求
  Future delete(String url, {Map<String, dynamic>? data}) async {
    final res = await _dio.delete(url, data: data);
    return _handleResult(res);
  }
  _handleResult(Response<dynamic> res){
    if (res.data['code'] == GlobalVariable.successCode){
      // 结果为10000时，表示请求业务成功，则需要返回得到的数据
      return res.data['data'];
    }
    // 增加提示
    PromptAction.showErrorToast(res.data['message']);
    // 抛出异常
    throw Exception(res.data['message']);
  }
  // 判断token是否过期
  Future<bool> _checkToken() async{
    // 1、获取刷新token
    final refreshToken = tokenManager.getRefreshToken();
    // 2、发请求
    // 3、在该请求中传入refreshToken
    // 4、根据状态码，来判断是否过期
    // 注意点：需要自己创建一个dio实例，为了避免使用之前的dio实例发请求，由于之前携带的是token，而不是refreshToken
    Dio dio = Dio();
    try{
      final res = await dio.post('${GlobalVariable.baseUrl}${HTTP_PATH.REFRESH_TOKEN}}',
      options: Options(headers:{'Authorization':'Bearer $refreshToken'}));
      if (res.data['code'] == 10000){
        // 刷新token成功
        // 将获取到的最新的token和refreshToken进行储存
        tokenManager.setToken(res.data['data']['token'],refreshToken: res.data['data']['refreshToken']);
        return true;
      }
      else {
        // 刷新token过期
        return false;
      }
    } catch (e) {
      return false;
    }
  }

  void _registerInterceptors(){
    _dio.interceptors.add(
      InterceptorsWrapper(
        // 请求拦截器
        onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
          // 获取token
          final token = tokenManager.getToken();
          // 如果token存在，则携带token
          if (token.isNotEmpty) {
            options.headers['Authorization'] = 'Bearer $token';
          }
          return handler.next(options);
        },
        // 响应拦截器
        onResponse: (Response response, ResponseInterceptorHandler handler) {
          // 针对于http请求的状态码，如果大于等于200且小于300，则表示请求成功，否则表示请求失败
          if (response.statusCode! >= 200 && response.statusCode! < 300){
            return handler.next(response);
          } else {
            // 4开头的表示客户端异常，也就是请求路径错误，或者token错误
            // 5开头的表示服务端异常
            // 提示用户
            PromptAction.showErrorToast(response.statusMessage!);
            // 返回一个错误的flutter，类似于promise
            return handler.reject(DioException(
              requestOptions:response.requestOptions,
              type: DioExceptionType.badResponse,
              error: response.statusMessage,
            ));
          }
        },
        // 错误拦截器
        onError: (DioException error, ErrorInterceptorHandler handler) async {
          if (error.response?.statusCode == 401) {
            String refreshToken = tokenManager.getRefreshToken();
            // 刷新token存在的情况
            if (refreshToken.isNotEmpty) {
              // 刷新token存在的情况
              // 判断是否过期，封装一个方法，返回布尔值，如果是true，则没有过期
              bool isExpire = await _checkToken();
              if (isExpire) {
                // 刷新token成功，重新发一次请求
                final res = await _dio.fetch(error.requestOptions);
                return handler.resolve(res);
              } else {
                // 刷新token过期或不存在
                tokenManager.deleteToken();
                eventBus.fire(LogoutEvent());
              }
            // 不存在
            } else {
              // 清除本地缓存,然后跳转到登录页
              tokenManager.deleteToken();
              // 在非页面组件中，没有context，所以没法使用Navigator.pushNamed进行跳转
              // 可以发布订阅模式
              // 1、发布一个消息
              eventBus.fire(LogoutEvent());
              // 2、其他需要跳转的位置，订阅消息，也就是接收消息
            }
          }
          return handler.next(error);
        },
      ),
    );
  }
}
final requestdio = Requestdio();